import BatchTable from "../utils/BatchTable"
import FeatureTable from "../utils/FeatureTable"
import * as THREE from "three"
class PNTSLoaderBase {
  fetchOptions: {}
  constructor() {
    this.fetchOptions = {}
  }
  load(e) {
    return fetch(e, this.fetchOptions)
      .then(t => {
        if (!t.ok) throw new Error(`Failed to load file "${e}" with status ${t.status} : ${t.statusText}`)
        return t.arrayBuffer()
      })
      .then(e => this.parse(e))
  }
  parse(e): any {
    const t = new DataView(e),
      r = String.fromCharCode(t.getUint8(0)) + String.fromCharCode(t.getUint8(1)) + String.fromCharCode(t.getUint8(2)) + String.fromCharCode(t.getUint8(3))
    console.assert("pnts" === r)
    const s = t.getUint32(4, !0)
    console.assert(1 === s)
    const n = t.getUint32(8, !0)
    console.assert(n === e.byteLength)
    const i = t.getUint32(12, !0),
      o = t.getUint32(16, !0),
      a = t.getUint32(20, !0),
      l = t.getUint32(24, !0),
      c = e.slice(28, 28 + i + o),
      h = new FeatureTable(c, 0, i, o),
      u = 28 + i + o,
      d = e.slice(u, u + a + l),
      p = new BatchTable(d, h.getData("BATCH_LENGTH") || h.getData("POINTS_LENGTH"), 0, a, l)
    return { version: s, featureTable: h, batchTable: p }
  }
}
export default class PNTSLoader extends PNTSLoaderBase {
  manager: THREE.LoadingManager
  constructor(e = THREE.DefaultLoadingManager) {
    super(), (this.manager = e)
  }
  parse(e) {
    const t = super.parse(e),
      { featureTable: r } = t,
      s = r.getData("POINTS_LENGTH"),
      n = r.getData("POSITION", s, "FLOAT", "VEC3"),
      i = r.getData("RGB", s, "UNSIGNED_BYTE", "VEC3")
    ;[
      "RTC_CENTER",
      "QUANTIZED_VOLUME_OFFSET",
      "QUANTIZED_VOLUME_SCALE",
      "CONSTANT_RGBA",
      "BATCH_LENGTH",
      "POSITION_QUANTIZED",
      "RGBA",
      "RGB565",
      "NORMAL",
      "NORMAL_OCT16P"
    ].forEach(e => {
      e in r.header && console.warn(`PNTSLoader: Unsupported FeatureTable feature "${e}" detected.`)
    })
    const o = new THREE.BufferGeometry()
    o.setAttribute("position", new THREE.BufferAttribute(n, 3, !1))
    const a = new THREE.PointsMaterial()
    ;(a.size = 2), (a.sizeAttenuation = !1), null !== i && (o.setAttribute("color", new THREE.BufferAttribute(i, 3, !0)), (a.vertexColors = !0))
    const l = new THREE.Points(o, a)
    ;(t.scene = l), (t.scene.featureTable = r)
    const c = r.getData("RTC_CENTER")
    return c && ((t.scene.position.x += c[0]), (t.scene.position.y += c[1]), (t.scene.position.z += c[2])), t
  }
}
